﻿using System.Threading.Tasks;

namespace System.IO
{
    internal static class StreamExtensions
    {
        public static int ReadUInt16(this Stream s)
        {
            int b1, b2;
            b1 = s.ReadByte();
            b2 = s.ReadByte();
            if (b2 == -1 || b1 == -1)
                return -1;
            if (BitConverter.IsLittleEndian)
                return b2 << 8 | b2;
            else
                return b1 << 8 | b2;
        }

        public static int ReadNetworkUInt16(this Stream s)
        {
            int b1, b2;
            b1 = s.ReadByte();
            b2 = s.ReadByte();
            if (b2 == -1 || b1 == -1)
                return -1;
            return b1 << 8 | b2;
        }

        public static void WriteUInt16(this Stream s, ushort data)
        {
            s.Write(BitConverter.GetBytes(data), 0, 2);
        }

        public static void WriteNetworkUInt16(this Stream s, ushort data)
        {
            s.WriteByte((byte)(data >> 8 & 0xFF));
            s.WriteByte((byte)(data & 0xFF));
        }

        public static long ReadUInt32(this Stream s)
        {
            int b1, b2, b3, b4;
            b1 = s.ReadByte();
            b2 = s.ReadByte();
            b3 = s.ReadByte();
            b4 = s.ReadByte();
            if (b4 == -1 || b3 == -1 || b2 == -1 || b1 == -1)
                return -1;
            if (BitConverter.IsLittleEndian)
                return b4 << 24 | b3 << 16 | b2 << 8 | b1;
            else
                return b1 << 24 | b2 << 16 | b3 << 8 | b4;
        }


        public static long ReadNetworkUInt32(this Stream s)
        {
            int b1, b2, b3, b4;
            b1 = s.ReadByte();
            b2 = s.ReadByte();
            b3 = s.ReadByte();
            b4 = s.ReadByte();
            if (b4 == -1 || b3 == -1 || b2 == -1 || b1 == -1)
                return -1;
            return b1 << 24 | b2 << 16 | b3 << 8 | b4;
        }

        public static void WriteUInt32(this Stream s, uint data)
        {
            s.Write(BitConverter.GetBytes(data), 0, 4);
        }

        public static void WriteNetworkUInt32(this Stream s, uint data)
        {
            s.WriteByte((byte)(data >> 24 & 0xFF));
            s.WriteByte((byte)(data >> 16 & 0xFF));
            s.WriteByte((byte)(data >> 8 & 0xFF));
            s.WriteByte((byte)(data & 0xFF));
        }

        public static int Read(this Stream s, byte[] data)
        {
            return s.Read(data, 0, data.Length);
        }
        public static Task<int> ReadAsync(this Stream s, byte[] data)
        {
            return s.ReadAsync(data, 0, data.Length);
        }

        public static void Write(this Stream s, byte[] data)
        {
            s.Write(data, 0, data.Length);
        }
        public static Task WriteAsync(this Stream s, byte[] data)
        {
            return s.WriteAsync(data, 0, data.Length);
        }

        public static int CopyBytesTo(this Stream s, byte[] buffer, int desiredLength)
        {
            int readCount = 0;
            while (readCount < desiredLength)
            {
                int read = s.Read(buffer, readCount, desiredLength - readCount);
                if (read == 0)
                    return readCount;
                readCount += read;
            }
            return readCount;
        }

    }
}

